package com.beyondbit.hr.report.support;

import com.beyondbit.hr.api.utils.NonRollbackException;
import com.beyondbit.hr.report.model.ReportResponse;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.export.ExporterConfiguration;
import net.sf.jasperreports.export.ReportExportConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class ReportConverter implements HttpMessageConverter<ReportResponse>, InitializingBean, ApplicationContextAware {

    final static public String PDF_VALUE = "application/pdf";

    final static public String XLS_VALUE = "application/vnd.ms-excel";

    public final static MediaType PDF = MediaType.valueOf(PDF_VALUE);
    public final static MediaType XLS = MediaType.valueOf(XLS_VALUE);
    public final static MediaType HTML = MediaType.TEXT_HTML;

    Logger logger = LoggerFactory.getLogger(ReportConverter.class);
    WebApplicationContext wac;

    public ReportRenderer reportRenderer(MediaType mediaType)throws NonRollbackException{
        Map<String, ReportRenderer> beans =  wac.getBeansOfType(ReportRenderer.class);
        for (Map.Entry<String, ReportRenderer> entry : beans.entrySet()){
            ReportRenderer reportRenderer = entry.getValue();

            if (reportRenderer.getSupportedMediaTypes().contains(mediaType)){
                return reportRenderer;
            }
        }

        throw new NonRollbackException("没有发现能渲染类型:"+mediaType.toString()+"的渲染器");
    }


    @Override
    public boolean canRead(Class<?> aClass, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class<?> aClass, MediaType mediaType) {
        boolean canWrite = false;
        if (ReportResponse.class.isAssignableFrom(aClass)){
            for (MediaType smt : getSupportedMediaTypes()){
                if (smt.isCompatibleWith(mediaType)){
                    canWrite = true;
                    break;
                }
            }
        }
        return canWrite;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Arrays.asList(PDF,XLS,HTML);
    }

    @Override
    public ReportResponse read(Class<? extends ReportResponse> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public void write(ReportResponse reportResponse, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        if (httpOutputMessage instanceof ServletServerHttpResponse) {
            ServletServerHttpResponse rsp = (ServletServerHttpResponse) httpOutputMessage;
            try{
                ReportRenderer reportRenderer = reportRenderer(mediaType);

                ExporterConfiguration exporterConfiguration = reportRenderer.defaultExporterConfiguration();
                ReportExportConfiguration reportExportConfiguration = reportRenderer.defaultReportExportConfiguration();

                reportRenderer.render(reportResponse.getJasperPrint(),reportExportConfiguration,exporterConfiguration,rsp.getBody());

            }catch (NonRollbackException|JRException e){
                throw new IOException(e);
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.wac = (WebApplicationContext) applicationContext;
    }
}
